package client;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import server.Crypto;
import server.Message;
import server.Message.MsgType;

public class Client {

    private DatagramSocket sock;
    private String myHash;
    long seq = 0;
    private UserGUI gui;
    private Map<String, Integer> areaNumbers = new HashMap<String, Integer>();
    private Map<String, BufferedWriter> file = new HashMap<String, BufferedWriter>();

    public Client(String myName, String hostIP, int hostPort,
            List<String> subscribedTo) {
        myHash = Crypto.hash(myName);
        try {
            sock = new DatagramSocket();
            sock.connect(new InetSocketAddress(hostIP, hostPort));
        } catch (SocketException e) {
            e.printStackTrace();
        }
        int index = 0;
        for (String sub : subscribedTo) {
            String subHash = Crypto.hash(sub);
            areaNumbers.put(subHash, index);

            File f = new File(myName + "_" + sub + ".txt");
            f.delete();
            try {
                f.createNewFile();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            try {
                FileWriter fstream = new FileWriter(f, true);
                BufferedWriter out = new BufferedWriter(fstream);
                file.put(subHash, out);
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                Message m = new Message(MsgType.SUB, myHash, seq++, subHash);
                byte[] buf = m.serialize().array();
                sock.send(new DatagramPacket(buf, buf.length));
            } catch (IOException e) {
                e.printStackTrace();
            }
            index++;

        }
        String[] ar = new String[subscribedTo.size()];
        gui = new UserGUI(myName, subscribedTo.size(), subscribedTo.toArray(ar));
        new Thread() {
            public void run() {
                consumeMessages();
            }
        }.start();
    }

    public void consumeMessages() {
        while (true) {
            byte[] buf = new byte[256];
            DatagramPacket pac = new DatagramPacket(buf, buf.length);
            try {
                sock.receive(pac);
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] smaller = new byte[pac.getLength()];
            System.arraycopy(buf, 0, smaller, 0, smaller.length);
            ByteBuffer bb = ByteBuffer.wrap(smaller);
            bb.flip();
            Message m = Message.deserialize(bb);
            appendFile(file.get(m.pubId), m.data);
            gui.updateArea(areaNumbers.get(m.pubId), m.data);
        }
    }

    private void appendFile(BufferedWriter out, String data) {
        try {
            out.write(data);
            out.write("\n");
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        String myName = args[0];
        String hostIP = args[1];
        int hostPort = Integer.parseInt(args[2]);
        List<String> subscribedTo = new LinkedList<String>();
        for (int i = 3; i < args.length; i++) {
            subscribedTo.add(args[i]);
        }
        Client client = new Client(myName, hostIP, hostPort, subscribedTo);
    }
}
